package com.wei.test.Util;

import com.wei.test.Constant.CachedConstant;
import com.wei.test.Service.LogService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

@Component
public class AppUtil {
    private final String[] IP_HEADER_CANDIDATES = {
            "X-Forwarded-For",
            "Proxy-Client-IP",
            "WL-Proxy-Client-IP",
            "HTTP_X_FORWARDED_FOR",
            "HTTP_X_FORWARDED",
            "HTTP_X_CLUSTER_CLIENT_IP",
            "HTTP_CLIENT_IP",
            "HTTP_FORWARDED_FOR",
            "HTTP_FORWARDED",
            "HTTP_VIA",
            "REMOTE_ADDR"};

    private final Map<Integer, String> rtcodeMessage = new HashMap<Integer, String>() {
        {
            put(-1, "失败");
            put(0, "成功");
        }
    };


    @Autowired
    private LogService logService;

    @Autowired
    private com.wei.test.Util.DateTimeUtil dateTimeUtil;

    @Autowired
    private com.wei.test.Util.JsonUtil jsonUtil;

    private void objTransform(Object value, List datas) {
        if (isPrimitive(value) || isPrimitiveWrapClass(value) || value instanceof Map)
            datas.add(value);
        else {
            Map temp = jsonUtil.bean2Map(value);
            if (temp != null)
                datas.add(temp);
        }
    }

    public Map getResult(Integer rtcode, Object... values) {
        Map result = new HashMap();
        result.put("status", rtcode);
        int len = values.length;

        result.put("message", rtcodeMessage.get(rtcode));

        if (len == 1 && (values[0] instanceof Map)) {
            result.put("data", values[0]);
            return result;
        }
        List data = new ArrayList();
        for (int i = 0; i < len; i++) {
            Object value = values[i];
            objTransform(value, data);
        }
        result.put("data", data);
        return result;
    }

    public Map getResult(Integer rtcode, List beans) {
        if (null == beans) {
            beans = new ArrayList();
        }
        Map result = new HashMap();
        List datas = new ArrayList();
        result.put("status", rtcode);
        result.put("message", rtcodeMessage.get(rtcode));

        for (int j = 0; j < beans.size(); j++) {
            Object value = beans.get(j);
            objTransform(value, datas);
        }

        result.put("data", datas);
        return result;
    }

    public Map getObjectDetails(Object o) {
        Map rs = new HashMap();
        Class cls = o.getClass();
        String className = cls.getName();
        String superClassName = cls.getSuperclass().toGenericString();
        Field[] fields = cls.getDeclaredFields();
        Method[] methods = cls.getDeclaredMethods();
        Class<?>[] interfaces = cls.getInterfaces();

        List filedList = new ArrayList();
        List methodList = new ArrayList();
        List interfaceList = new ArrayList();

        for (Field f : fields) {
            filedList.add(f.getName());
        }

        for (Method m : methods) {
            methodList.add(m.getName());
        }

        for (Class<?> i : interfaces) {
            interfaceList.add(i.getName());
        }

        rs.put("className", className);
        rs.put("superClassName", superClassName);
        rs.put("field", filedList);
        rs.put("method", methodList);
        rs.put("interface", interfaceList);
        return rs;
    }

    public boolean isPrimitive(Object o) {
        return o.getClass().isPrimitive();
    }

    public boolean isPrimitiveWrapClass(Object o) {
        if (o instanceof String ||
                o instanceof Integer ||
                o instanceof Long ||
                o instanceof Double ||
                o instanceof Boolean ||
                o instanceof Character ||
                o instanceof Float)
            return true;
        return false;
    }

    public String getRemoteHost(HttpServletRequest request) {
        for (String header : IP_HEADER_CANDIDATES) {
            String ipList = request.getHeader(header);
            if (ipList != null && ipList.length() != 0 && !"unknown".equalsIgnoreCase(ipList)) {
                String ip = ipList.split(",")[0];
                return ip;
            }
        }

        return request.getRemoteAddr();
    }

    public String getRequestBody(HttpServletRequest request) throws IOException {
        BufferedReader streamReader = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
        StringBuilder responseStrBuilder = new StringBuilder();
        String inputStr;

        while ((inputStr = streamReader.readLine()) != null)
            responseStrBuilder.append(inputStr);

        return responseStrBuilder.toString();

    }

    public Object getAnnotationClass(Class tClass, ProceedingJoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Annotation[] al = method.getAnnotations();
        Object instance = method.getAnnotation(tClass);
        return instance;
    }

    public void setResponse(HttpServletResponse response, int rtCode) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        String payLoad = jsonUtil.obj2Str(getResult(rtCode));
        writer.write(payLoad);
        writer.flush();
        writer.close();
    }

    public Map getJwtToken(HttpServletRequest request) {
        String authHeader = request.getHeader("Authorization");

        if (authHeader == null || !authHeader.startsWith("token ")) {
            logService.error("Http头信息错误");
            return null;
        }

        String token = authHeader.substring(6);
        Claims claims = Jwts.parser().setSigningKey(CachedConstant.jwtPrivateKey.getBytes()).parseClaimsJws(token).getBody();
        Map jwtToken = (Map) claims.get("jwtToken");
        return jwtToken;
    }

    public String generateJwtToken(String id) {
        String expireTime = dateTimeUtil.plusMinutes(1);
        Map token = new HashMap();
        token.put("id", id);
        token.put("expiration", expireTime);
        String jwtToken = Jwts.builder().setSubject("loginToken").claim("jwtToken", token).setIssuedAt(new Date())
                .signWith(SignatureAlgorithm.HS256, CachedConstant.jwtPrivateKey.getBytes()).compact();

        return jwtToken;
    }
}
